Skip to content

fix(security): filepath.IsLocal sanitisers for CodeQL path/command-injection#44

Merged
aksOps merged 1 commit intomainfrom
fix-security-codeql
Apr 23, 2026
Merged

fix(security): filepath.IsLocal sanitisers for CodeQL path/command-injection#44
aksOps merged 1 commit intomainfrom
fix-security-codeql

Conversation

@aksOps
Copy link
Copy Markdown
Contributor

@aksOps aksOps commented Apr 23, 2026

Closes 8 CodeQL alerts (1 critical command-injection + 7 high path-injection). Underlying code was already safe via regex/segment validation; CodeQL just doesn't recognise those as sanitisers. Added filepath.IsLocal checks at the tainted sinks — CodeQL-recognised, stricter than our existing checks, so this is pure belt-and-braces.

Sites:

  • internal/notes/notes.go::resolvePath (covers Read/Write/Delete/List)
  • internal/notes/history.go::autoCommit + History
  • internal/api/project.go::projectMiddleware

Tests pass locally.

…d-injection

CodeQL flagged 8 alerts (1 critical command-injection + 7 high
path-injection) in notes and project handlers. The underlying code is
already safe — ValidateKey/IsValidSlug reject path-dangerous input —
but CodeQL's static analysis doesn't recognise our regex/segment
sanitisers, so the warnings persisted.

Adds filepath.IsLocal() checks at the tainted sinks:
- internal/notes/notes.go::resolvePath  (covers Read/Write/Delete/List)
- internal/notes/history.go::autoCommit + History
- internal/api/project.go::projectMiddleware

filepath.IsLocal is the CodeQL-recognised sanitiser for Go path injection;
it's stricter than our existing checks so this is pure belt-and-braces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aksOps aksOps enabled auto-merge (squash) April 23, 2026 05:16
@aksOps aksOps merged commit 940c33d into main Apr 23, 2026
12 checks passed
@aksOps aksOps deleted the fix-security-codeql branch April 23, 2026 05:20
aksOps added a commit that referenced this pull request Apr 23, 2026
CodeQL alert #33 (Critical): exec.Command("git", ...) in runGit
received user-controlled strings (commit message bytes from author /
subject, and paths from note keys). Although exec.Command uses argv
(no shell) which makes the standard shell-injection vector inert, git
itself has flag-based attack surface (e.g. `--upload-pack=cmd`,
`-c core.sshCommand=...`) that CodeQL is right to flag.

Defense in depth:

1. `runGit` now enforces:
   - notesDir must be non-empty and must not start with "-" (prevents
     it being parsed as a git top-level flag).
   - args[0] must be in a closed allow-list of subcommands (init /
     config / add / log). Commit is deliberately routed elsewhere
     (see #2).
   - Any arg after a literal "--" must satisfy filepath.IsLocal —
     this continues the sanitiser from PR #44 and is what CodeQL
     recognises.

2. `gitCommit` is a new helper that runs `git commit --no-gpg-sign
   -F -` and pipes the message via stdin. The message bytes therefore
   never appear in argv, cutting the only remaining taint flow from
   user input to exec.Command args.

3. autoCommit's commit call switched from runGit(..., "commit", "-m",
   msg) to gitCommit(notesDir, msg).

Tested locally: 104/104 tests passing in internal/notes/.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant